package com.kly.chatter.api.application.controller.im;

import cn.hutool.core.date.DateUtil;
import com.alibaba.csp.sentinel.annotation.SentinelResource;
import com.alibaba.fastjson.JSONObject;
import com.fqgj.base.services.redis.RedisClient;
import com.fqgj.common.api.Response;
import com.fqgj.common.api.annotations.ParamsValidate;
import com.fqgj.common.utils.CollectionUtils;
import com.fqgj.log.factory.LogFactory;
import com.fqgj.log.interfaces.Log;
import com.google.api.client.util.Lists;
import com.jsoniter.output.JsonStream;
import com.kly.chatter.api.application.controller.im.req.*;
import com.kly.chatter.api.application.controller.im.rsp.*;
import com.kly.chatter.api.application.dto.UserCodeRequest;
import com.kly.chatter.api.application.utils.Result;
import com.kly.sc.api.application.constant.ApiRedisKeys;
import com.kly.sc.api.application.helper.RequestLocalInfo;
import com.kly.sc.api.application.utils.RpcUtils;
import com.kly.sc.api.infras.enums.RestCodeEnum;
import com.kly.sc.api.infras.exception.ApplicationException;
import com.kly.sc.api.infras.handler.ApiResponse;
import com.kly.sc.api.integration.im.IMService;
import com.kly.service.MemberService;
import com.kly.user.chatterService.ChatService;
import com.kly.user.dto.*;
import com.kly.user.dto.chatter.request.ChatListReq;
import com.kly.user.dto.chatter.request.ConversationOPReq;
import com.kly.user.dto.chatter.response.ChatListDto;
import com.kly.user.dto.chatter.response.UserAccount;
import com.kly.user.dto.chatter.response.UserLevelDto;
import com.kly.user.enums.ConversationOPTypeType;
import com.kly.user.service.AuthLoginService;
import com.kly.user.service.UserConversationService;
import com.kly.user.service.UserService;
import com.kly.user.service.WlmService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import javax.validation.Valid;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Objects;

/**
 * @author linqu
 */
@Api(value = "会话相关操作类", tags = {"会话相关操作类"})
@RestController
@RequestMapping("/api/chat")
public class IMController {

    private static final Log logger = LogFactory.getLog(IMController.class);
    @Resource
    ChatService chatService;
    @Resource
    WlmService wlmService;
    @Resource
    UserService userService;
    @Resource
    IMService imService;
    @Resource
    AuthLoginService authLoginService;
    @Resource
    MemberService memberService;
    @Resource
    RedisClient redisClient;

    @Resource
    UserConversationService userConversationService;

    /**
     * Save chat & Remove chat & Topping chat接口
     */
    @ApiOperation("Save chat & Remove chat & Topping chat接口")
    @SentinelResource
    @RequestMapping(value = "/opChat", method = {RequestMethod.POST})
    public Response newMatchList(@Valid @RequestBody OpRequest request, BindingResult results) {
        if (results.hasErrors()) {
            logger.error("TheRequestParamsError:{}, errorMsg:{}", JSONObject.toJSONString(request), JSONObject.toJSONString(results.getAllErrors()));
            return Response.error();
        }

        final ConversationOPTypeType conversationOPTypeType = ConversationOPTypeType.fromType(request.getConversationType());
        if (Objects.isNull(conversationOPTypeType)) {
            throw new ApplicationException("The value of parameter [conversationType] is illegal");
        }

        ConversationOPReq conversationOPReq = ConversationOPReq.builder().build();
        BeanUtils.copyProperties(request, conversationOPReq);
        Response response = chatService.addConversation(conversationOPReq);
        if (!response.isSuccess()) {
            return response;
        }
        return Response.ok();
    }

    /**
     * 获取融云平台会话token
     */
    @ApiOperation("获取融云平台会话token")
    @ResponseBody
    @SentinelResource
    @RequestMapping(value = "/getIMtoken", method = RequestMethod.POST)
    public ApiResponse getIMtoken(@RequestBody UserCodeRequest request) {


        Map<String, Object> resultMap = new HashMap<>(1);

        // 判断是否存在融云平台token, 若存在直接返回
        final String rongCloudToken = RpcUtils.getResult(authLoginService.getRongCloudToken(request.getUserCode()));
        if (StringUtils.isNotBlank(rongCloudToken)) {
            resultMap.put("token", rongCloudToken);
            return ApiResponse.ok(resultMap);
        }

        // RPC获取用户信息
        UserInfoDto userInfoDto = getCurrentUserInfo(request.getUserCode());
        // 使用userInfoDto注册融云账户，注册成功后拿到token
        String token = imService.getToken(request.getUserCode(), userInfoDto.getNickName(), userInfoDto.getAvatarUrl());
        // 封装token返回给客户端
        resultMap.put("token", token);

        return ApiResponse.ok(resultMap);
    }

    /**
     * chat列表
     */
    @ApiOperation("chat列表")
    @ResponseBody
    @SentinelResource
    @RequestMapping(value = "/modelChatList", method = {RequestMethod.POST})
    @ParamsValidate
    public Response modelChatList(@RequestBody ChatListRequest chatListRequest) {
        final String chatterUserCode = RequestLocalInfo.getCurrentUser().getUserCode();
        try {
            logger.info("==modelChatList1  ==,聊天列表请求参数:{},chatterCode:{}", JsonStream.serialize(chatListRequest), chatterUserCode);
            final ChatListReq chatListReq = ChatListReq.builder().chatterUserCode(chatterUserCode).modelUserCode(chatListRequest.getModelUserCode()).sessionSaveFlag(chatListRequest.getSessionSaveFlag()).pageNum(chatListRequest.getPageNum()).pageSize(chatListRequest.getPageSize()).nickName(chatListRequest.getNickName()).build();
            final ChatListDto result = RpcUtils.getResult(chatService.chatList(chatListReq));
            if (result != null) {
                List<UserAccount> conversationChatList = result.getConversationChatList();
                for (UserAccount userAccount : conversationChatList) {
                    try {
                        logger.info("==modelChatList1 处理循环  ==,聊天列表请求参数:{},chatterCode:{},account:{}", JsonStream.serialize(chatListRequest), chatterUserCode, JsonStream.serialize(userAccount));
                        String latestSendTime = userAccount.getLatestSendTime();
                        String userMember = redisClient.get(ApiRedisKeys.USER_MEMBER.getValue(), userAccount.getUserCode());
                        if (StringUtils.isNotEmpty(userMember)) {
                            userAccount.setMember(true);
                        }
                        if (latestSendTime != null) {
                            Date date = DateUtil.parse(latestSendTime);
                            // 判断日期是否为当天
                            if (DateUtil.isSameDay(date, DateUtil.date())) {
                                // 转为年月日格式
                                userAccount.setLatestSendTime(DateUtil.format(date, "HH:mm"));
                            } else {
                                // 判断日期是否为当年
                                if (DateUtil.year(date) == DateUtil.year(DateUtil.date())) {
                                    // 转为月日格式
                                    userAccount.setLatestSendTime(DateUtil.format(date, "MM-dd"));
                                } else {
                                    // 转为年月日格式
                                    userAccount.setLatestSendTime(DateUtil.formatDate(date));
                                }
                            }
                        }
                    } catch (Exception e) {
                        logger.error("==modelChatList1 循环产生异常  ==,聊天列表请求参数:{},chatterCode:{},account:{}", JsonStream.serialize(chatListRequest), chatterUserCode, JsonStream.serialize(userAccount), e);
                    }

                }
                return Response.ok(result);
            } else {
                logger.info("==modelChatList1 返回结果为空  ==,聊天列表请求参数:{},chatterCode:{}", JsonStream.serialize(chatListRequest), chatterUserCode);
                return Response.ok(result);
            }
        } catch (Exception e) {
            logger.error("==modelChatList1 循环产生异常  ==,聊天列表请求参数:{},account:{}", JsonStream.serialize(chatListRequest), chatterUserCode, e);
            return Response.ok();
        }

    }

    /**
     * 获取个人信息，该接口用于主播的会话列表的初始化数据加载
     */
    @ApiOperation("获取个人信息")
    @ResponseBody
    @RequestMapping(value = "/user/info", method = {RequestMethod.POST})
    @ParamsValidate
    public Result<UserInfoResp> userInfo(@RequestBody GetUserInfoRequest request) {

        final UserInfoDto userInfo = RpcUtils.getResult(userService.getUserByUserCode(request.getUserCode()));
        if (userInfo == null) {
            return Result.ok();
        }
        final UserInfoResp user = UserInfoResp.builder().userCode(userInfo.getUserCode()).nickName(userInfo.getNickName()).avatarUrl(userInfo.getAvatarUrl()).online(userInfo.getOnline()).build();
        if (StringUtils.isNotBlank(request.getModelUserCode())) {
            final UserConversationDto userConversation = userConversationService.getUserConversation(request.getUserCode(), request.getModelUserCode());
            if (userConversation != null) {
                user.setToppingFlag(userConversation.getToppingFlag());
                user.setBlackFlag(userConversation.getBlockStatus());
                final Response<Integer> chatLevelResp = chatService.getChatLevel(request.getUserCode(), request.getModelUserCode());
                if (chatLevelResp.isSuccess() && chatLevelResp.getData() != null) {
                    user.setLevel(chatLevelResp.getData());
                }
            }
        }
        user.setMember(RpcUtils.getResult(memberService.ifMember(request.getUserCode())));
        return Result.ok(user);
    }

    /**
     * 获取主播会话列表中在线用户相关数据
     */
    @ApiOperation("获取主播会话列表中在线用户相关数据")
    @ParamsValidate
    @ResponseBody
    @RequestMapping(value = "/user/status/list", method = {RequestMethod.POST})
    public Result<List<UserInfoVo>> onlineOnlineList(@RequestBody GetUserStatusRequest request) {
        final String chatterUserCode = RequestLocalInfo.getCurrentUser().getUserCode();
        final List<UserLevelDto> userLevelDtoList = RpcUtils.getResult(chatService.listUserChatLevel(chatterUserCode, request.getModelUserCode()));
        if (CollectionUtils.isEmpty(userLevelDtoList)) {
            return Result.ok();
        }
        List<UserInfoVo> userInfoVos = Lists.newArrayList();
        for (UserLevelDto dto : userLevelDtoList) {
            final Boolean isMember = RpcUtils.getResult(memberService.ifMember(dto.getUserCode()));
            userInfoVos.add(UserInfoVo.toVo(dto.getUserCode(), dto.getChatLevel(), isMember, dto.getNickName(), dto.getAvatarUrl()));
        }
        return Result.ok(userInfoVos);
    }

    /**
     * 用户行为接口
     */
    @ApiOperation("用户行为接口")
    @ResponseBody
    @SentinelResource
    @RequestMapping(value = "/addAction", method = {RequestMethod.POST})
    @ParamsValidate
    public Response addAction(@RequestBody DoUserOperateRequest doUserReq) {

        // 添加wlmUser信息
        AddWlmReq req = new AddWlmReq();
        BeanUtils.copyProperties(doUserReq, req);
        req.setUserCode(doUserReq.getModelUserCode());
        req.setUserCodeFriend(doUserReq.getUserCodeFriend());

        final AddWlmUserDto result = RpcUtils.getResult(wlmService.doAction(req));
        if (Objects.isNull(result)) {
            return Response.ok();
        }

        return Response.ok(AddWlmResponse.builder().userCode(doUserReq.getModelUserCode()).matched(result.isMatched()).build());
    }

    @ApiOperation("用户Profile信息")
    @ResponseBody
    @SentinelResource
    @RequestMapping(value = "/modelUserProfile", method = {RequestMethod.POST})
    public Response modelUserProfile(@RequestBody ModelUserProfileRequest request) {

        final UserInfoDto userInfo = RpcUtils.getResult(userService.getUserByUserCode(request.getUserCode()));
        final UserInfoDto modelInfo = RpcUtils.getResult(userService.getUserByUserCode(request.getModelUserCode()));

        final ModelUserProfileRsp modelUserProfileRsp = ModelUserProfileRsp.builder().build();
        if (Objects.nonNull(userInfo)) {
            String userMember = redisClient.get(ApiRedisKeys.USER_MEMBER.getValue(), userInfo.getUserCode());
            if (StringUtils.isNotEmpty(userMember)) {
                modelUserProfileRsp.setMember(true);
            }
            final Response<Integer> userChatLevel = userService.getUserChatLevel(request.getUserCode(), request.getModelUserCode());
            final UserProfileVO userProfileVO = getUserProfileVO(userInfo, userChatLevel.getData());
            modelUserProfileRsp.setUserAccount(userProfileVO);
        }
        if (Objects.nonNull(modelInfo)) {
            final UserProfileVO modelProfileVO = getUserProfileVO(modelInfo, 0);
            modelProfileVO.setState("USA");
            modelProfileVO.setCity("America");
            modelUserProfileRsp.setModelAccount(modelProfileVO);
        }
        Map<String, Object> params = new HashMap<>();
        params.put("deleted", 0);
        params.put("toUserCode", request.getModelUserCode());
        List<String> userCodeList = new ArrayList<>();
        userCodeList.add(request.getUserCode());
        params.put("list", userCodeList);
        Map<String, UserConversationRecordDto> userConversationMsgNum = userConversationService.getUserConversationMsgNum(params);
        if (userConversationMsgNum.get(request.getUserCode())!=null){
            modelUserProfileRsp.setMsgNum(userConversationMsgNum.get(request.getUserCode()).getConversationsNumber());
        }

        return Response.ok(modelUserProfileRsp);
    }

    private UserProfileVO getUserProfileVO(UserInfoDto userInfo, Integer userLevel) {
        if (Objects.isNull(userInfo)) {
            return UserProfileVO.builder().build();
        }

        SimpleDateFormat sdf = new SimpleDateFormat("MMM dd yyyy,HH:mm", Locale.ENGLISH);
        String localTime = "";
        if (Objects.nonNull(userInfo.getLocalTime())) {
            localTime = sdf.format(userInfo.getLocalTime());
        }

        return UserProfileVO.builder().level(userLevel).userCode(userInfo.getUserCode()).nickName(userInfo.getNickName())
                .age(userInfo.getAge()).city(null).online(userInfo.getOnline()).localTime(localTime)
                .gender(userInfo.getGender()).lookingFor(userInfo.getLookingFor()).interests(userInfo.getInterests())
                .aboutme(userInfo.getAboutMe()).birthday(DateUtil.format(userInfo.getBirthday(), "MM/dd/yyyy"))
                .avatarUrl(userInfo.getAvatarUrl()).lat(userInfo.getLat()).lng(userInfo.getLng()).state(userInfo.getState()).city(userInfo.getCity())
                .build();
    }

    /**
     * 获取用户信息
     */
    private UserInfoDto getCurrentUserInfo(String userCode) {
        final UserInfoDto userInfoDto = RpcUtils.getResult(userService.getUserByUserCode(userCode));
        if (Objects.isNull(userInfoDto)) {
            throw new ApplicationException(RestCodeEnum.USER_NOT_EXIST_ERROR);
        }
        return userInfoDto;
    }

}


